﻿using System;
using System.Collections;
using System.Configuration;
using System.Web;
using System.Web.Caching;

namespace ArienToolkits.Caching
{
    /// <summary>
    /// Web缓存提供程序
    /// </summary>
    public class WebCacheProvider : ICache
    {
        /// <summary>
        /// 缓存键前缀配置
        /// </summary>
        private static readonly string _cachePrefixKey = "Cache.CachePrefix";
        /// <summary>
        /// 缓存过期时间配置
        /// </summary>
        private static readonly string _cacheExpirationKey = "Cache.CacheExpiration";

        public void Save(string key, object obj, bool addSqlDependency = false)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("被缓存参数值不能为空!");
            }
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Cache.Get(key) == null)
                {
                    if (addSqlDependency)
                    {
                        string tableName = ConfigurationManager.AppSettings[_cachePrefixKey] + key;
                        if (string.IsNullOrEmpty(tableName))
                        {
                            throw new ArgumentException(string.Format("请追加<add key=\"{0}\" value=\"\">节点到站点配置文件中！已开启数据库依赖缓存。", _cachePrefixKey));
                        }
                        HttpContext.Current.Cache.Insert(key, obj, new SqlCacheDependency("Zues", tableName));
                    }
                    else
                    {
                        int expiration = 20;
                        string tmpExpiration = ConfigurationManager.AppSettings[_cacheExpirationKey];
                        if (!int.TryParse(tmpExpiration, out expiration))
                        {
                            System.Diagnostics.Trace.WriteLine("配置文件中未出现缓存默认超时时间配置节点，如需追加，则在站点配置文件中添加<add key=\"{0}\" value=\"20\">的节点。否则，默认超时时间将被设定为20分钟");
                        }

                        HttpContext.Current.Cache.Insert(key, obj, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(expiration));
                    }
                }
                else
                {
                    HttpContext.Current.Cache[key] = obj;
                }
            }
        }

        public T Get<T>(string key)
        {
            object obj = this[key];
            if (obj == null)
            {
                return default(T);
            }
            return (T)obj;
        }

        public T Get<T>(string key, Func<object> action, bool addSqlDependency = false)
        {
            if (action == null)
            {
                throw new ArgumentNullException("回调函数不能为空");
            }

            object obj = this[key];

            if (obj == null)
            {
                obj = action.Invoke();
                if (obj != null)
                {
                    Save(key, obj, addSqlDependency);
                    return (T)obj;
                }
                else
                {
                    return default(T);
                }
            }

            return (T)obj;
        }

        public object Remove(string key)
        {
            object obj = this[key];

            if (obj != null)
            {
                if (HttpContext.Current != null)
                {
                    HttpContext.Current.Cache.Remove(key);
                }

                return obj;
            }

            return null;
        }

        public void Clear()
        {
            IDictionaryEnumerator enumerator = HttpContext.Current.Cache.GetEnumerator();

            while (enumerator.MoveNext())
            {
                HttpContext.Current.Cache.Remove(enumerator.Key.ToString());
            }
        }

        public object this[string key]
        {
            get
            {
                if (HttpContext.Current != null)
                    return HttpContext.Current.Cache.Get(key);
                return null;
            }
        }
    }
}
